﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Management;
using System.Net;
using System.Text;
using System.Xml;

namespace Universe.Farm.Builtin.LocalComputerListener
{
    public static class WmiNetworkUtils
    {
        public static XmlElement BuildTcpIpReport(out List<IPAddress> multicastAddresses)
        {
            XmlDocument doc = new XmlDocument();
            doc.AppendChild(doc.CreateElement("TCPIP"));
            multicastAddresses = new List<IPAddress>();

            try
            {
                string wql = "SELECT * FROM Win32_NetworkAdapterConfiguration";
                using (ManagementObjectSearcher query = new ManagementObjectSearcher(wql))
                {
                    Dictionary<string, object> history = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase);
                    foreach (ManagementBaseObject mo in query.Get())
                    {
                        XmlElement adapter = doc.CreateElement("Adapter");
                        string description = (string)mo.Properties["Description"].Value;
                        bool ipEnabled = Convert.ToBoolean(mo.Properties["IpEnabled"].Value);
                        string[] addresses = (string[])mo.Properties["IPAddress"].Value;
                        string[] subNets = (string[])mo.Properties["IPSubnet"].Value;
                        string mac = (string)mo.Properties["MACAddress"].Value;
                        bool enableFilter = Convert.ToBoolean(mo.Properties["IPFilterSecurityEnabled"].Value);

                        string[] filterProtocols = (string[])mo.Properties["IPSecPermitIPProtocols"].Value;
                        string[] filterTcpPorts = (string[])mo.Properties["IPSecPermitTCPPorts"].Value;
                        string[] filterUdpPorts = (string[])mo.Properties["IPSecPermitUDPPorts"].Value;

                        if (!string.IsNullOrEmpty(description))
                            adapter.SetAttribute("Name", description);

                        adapter.SetAttribute("Enabled", ipEnabled.ToString().ToLower());

                        if (ipEnabled)
                        {
                            List<IPAddress> mlist;
                            adapter.SetAttribute("IP", FormatAddr(addresses, subNets, out mlist));
                            if (ipEnabled)
                                multicastAddresses.AddRange(mlist);

                            adapter.SetAttribute("Filter", enableFilter ? "on" : "off");
                        }

                        if (!string.IsNullOrEmpty(mac))
                            adapter.SetAttribute("MAC", mac);

                        if (!history.ContainsKey(adapter.OuterXml))
                        {
                            doc.DocumentElement.AppendChild(adapter);
                            history[adapter.OuterXml] = null;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("Failed to build Tcp IP Report" + Environment.NewLine + ex);
            }


            return doc.DocumentElement;
        }

        private static string FormatAddr(string[] addresses, string[] nets, out List<IPAddress> multicastAddresses)
        {
            multicastAddresses = new List<IPAddress>();
            if (addresses == null)
                return string.Empty;

            StringBuilder ret = new StringBuilder();
            for (int i = 0; i < addresses.Length; i++)
            {
                string ip = addresses[i];
                string subNet = nets.Length > i ? nets[i] : "";

                ip = ip == null ? "" : ip.Trim();
                subNet = subNet == null ? "" : subNet.Trim();

                string item = ip == "" ? "" : (ip + (subNet == "" ? "" : " / " + subNet));
                if (item != null)
                    ret.Append(ret.Length == 0 ? "" : "; ").Append(item);

                if (!string.IsNullOrEmpty(ip) && !string.IsNullOrEmpty(subNet))
                {
                    IPAddress a1;
                    IPAddress mask;
                    if (IPAddress.TryParse(ip, out a1) && IPAddress.TryParse(subNet, out mask))
                    {
                        if (!IPAddress.IsLoopback(a1))
                        {
                            byte[] b1 = a1.GetAddressBytes();
                            byte[] bNew = new byte[b1.Length];
                            if (b1.Length == 4)
                            {
                                byte[] b2 = mask.GetAddressBytes();
                                for(int j=0; j<b1.Length; j++)
                                {
                                    byte newByte = (byte) (b1[j] | ((~b2[j]) & 0xFF));
                                    bNew[j] = newByte;
                                }

                                IPAddress mcip = new IPAddress(bNew);
                                multicastAddresses.Add(mcip);
                                Debug.WriteLine(
                                    string.Format(
                                        "{0} / {1}: [{2}]",
                                        ip,
                                        subNet,
                                        mcip
                                        ));

                            }

                        }
                    }
                }



            }

            return ret.ToString();
        }


    }
}